/*
 *  object-base.h
 *  joosVM
 *
 *  Created by Smári Waage on 14.8.2009.
 *  Copyright 2009 smari.org. All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. *
 */

#ifndef objects_root___ 
#define objects_root___ 

#include "heap.h"
#include "trace-recorder.h"

#define OBJECTS_LIST(T)  \
T(Pointer,		"Pointer",		0) \
T(Smi,			"Smi",			0) \
T(HeapObject,	"HeapObject",	1) \
T(Integer,		"Integer",		10)\
T(Float,		"Float",		11)\
T(Long,			"Long",			12)\
T(Double,		"Double",		13)\
T(Array,		"Array",		20)\
T(StaticArray,	"StaticArray",	21)\
T(ByteArray,	"ByteArray"		22)\
T(String,		"String",		23)\
T(HashTable,	"HashTable",	24)\
T(MethodArea,	"MethodArea",	25)\
T(JField,	"JField",	30)\
T(JStaticField, "JStaticField", 31)\
T(JAbstractMethod, "JAbstractMethod",	32)\
T(JMethod,	"JMethod",	33)\
T(JType,		"JType",		34)\
T(Instance,		"Instance",		35)\
T(Frame,		"Frame",		41)\
T(Stack,		"Stack",		42)




//Object model layout
//use taged pointer 4byte aligned
//Everything is an object.
/*
 Pointer
 -Smi
 
 -HeapObject		1
 --Numeric   
 ---Integer		10
 ---Float		11
 ---Long			12
 ---Double		13
 
 --Array			20
 ---StaticArray  21
 ---ByteArray	22
 ----String		23
 ---HashTable    24
 ----MethodArea  25
 
 --JField				30
 ---JStaticField		31
 ---JAbstractMethod	32
 ----JMethod			33
 --JType				34
 --Instance				35
 
 --Frame		41
 --Stack		42
 
 */
// We use direct pointers. 
// All pointers allocated in the heap are 4 bit aligned.
// The least significant two bits of our 4 bit aligned heap pointer 
// will always be 00. We use these two bit to tag the pointer
// to avoid allocating memory for small integers.

//Note only using one bit, can use another...
// 0 = Small integer (31 bit integer)
// 1 = HeapObject pointer
enum Tag {
	small_integer_tag = 0,
	heap_object_tag = 1
};

const int kPointerSize = sizeof(void*);
const int kDoubleSize = sizeof(double);
const int k2PointerSize = kPointerSize *2;

const int kBitsPerByte = 8;
const int kBitsPerPointer = kPointerSize * kBitsPerByte;


//Pointer is just a base class, without any slots, so it will never 
//exist in the heap. TODO: Need better name.
class Pointer{
public:
	bool isSmi(){ return tag() == small_integer_tag; }
	bool isHeapObject(){return tag() == heap_object_tag;}
	
	static const int kHeaderSize = 0;
	
protected:
	// Extract the least (two) significant bits from the pointer
	inline Tag tag() { return (Tag) ((int)this & 1); }	
};




/*
 * Numeric
 *
 * |	+HeapObject			|
 * +------------------------+
 * |		numeric			|
 * |		.				|
 * +------------------------+
 */

class Integer : public Pointer{
public:
	void setValue(int val){
		*(int*)this = val; 
	}
	
	int value(){
		return *(int*)this;
	}
	
};

class Float : public Pointer{
public:
	void setValue(float val){
		*(float*)this = val;
	}

	float value(){	
		return *(float*)this;
	}
	static Float* Initalize(float value){
		Float* f;
		f->setValue(value);
		return f;
	}
};

class Long : public Pointer{
public:
	void setValue(long long value){
		*(long long*)this = value; 
	}
	long long value(){	
		return *(long long*)this;
	}
	inline static Long* firstpart(long long value){
		return (Long*)value;
	}
	inline static Long* lastpart(long long value){
		return (Long*)(value<<32);
	}
};

class Double : public Pointer{
public:
	void setValue(double value){
	*(double*)this = value; 
	}
	double value(){
		return *(double*)this;
	}
	inline static Double* firstpart(double value){
		return (Double*)(uint64_t)value;
	}
	inline static Double* lastpart(double value){
		return (Double*)((uint64_t)value<<32);
	}
};


/*
 * Smi - small integer
 *	store a small int in the pointer(save space)
 *  smi never exists on it's onwn on the heap.
 */
class Smi: public Pointer {
public:
	// Shift pointer to places to the right to get the smi value
	int value() { 
		REQUIRE(this->isSmi())
		return ((int) this >> kSmiTagSize); 
	}
	
	static Smi* fromInt(int value) { 
		REQUIRE(isValid(value))
		// TODO: if (!isValid(value)) signal error
		return (Smi*)(value << kSmiTagSize); 
	}
	
	static bool isValid(int value) { 
		return (value >= kMinValue) && (value <= kMaxValue); 
	}
	
	static const int kSmiTagSize = 1;
	
	// Min and max limits for Smi values.
	static const int kMinValue = -(1 << (kBitsPerPointer - (kSmiTagSize + 1)));
	static const int kMaxValue = (1 << (kBitsPerPointer - (kSmiTagSize + 1))) - 1; 
};

//To put the methods somewhere
class InternalType: public Pointer{
	
};

#endif
